 #!/usr/bin/python
 # -*- coding: utf-8 -*-
 
 # Echo server program
import socket
import os
from filterrules import *
import time

HOSTLISTEN = ''			# Symbolic name meaning the local host
PORTLISTEN = 9870		# Arbitrary non-privileged port between bbw1 and server agent
ANOMALYHOST = '' # ip of AnomalyChecker
ANOMALYPORT = 60007 # port to send AnomalyChecker


class Mediator:

	def __init__(self):
		self.message=(orderno,protokol,srcip,srcport,dstip,dstport,action)=map(lambda x: None, range(0,7))
		#self.message=["192.*.*.*"]
		#self.message=["12","tcp","192.168.1.*","20","192.168.*.30","30","accept"] # will be commented
		self.reply = None	
		#self.reply="OK"  # will be blank string
		self.basestr="iptables -I FORWARD "
		self.starttime=self.stoptime=0
		
	def listenForMessage(self,port):
	
		s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
		s.bind((HOSTLISTEN, port))
		s.listen(1)
		conn, addr = s.accept()
		print 'Connected by', addr
		while 1:
			data = conn.recv(1024)	# recv from java application
			#print (data==None)
	    		if not data: break
	    		conn.send("OK")	# send the data received to the java application
			conn.close()
	    		li=data.split(',')
			li=map(lambda x: x.strip(),li) ## take out the whitespace
			self.message=li
			print "Message taken:", self.message
			self.basestr=self.basestr+self.message[0]+" " # this is ok
			#print message	
			break
		s.close()
		
	def sendAndReceive(self,ip,port):
		li=[]
		while 1:
			try:
				"trying to connect to the anomaly checker"
				ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
				ss.connect((ip, port))
				print "connected to the anomaly checker"
				break;
			
			except:
				continue #try till connect to the AnomalyChecker
		
		li=self.message
		li[0]=li[0]+": "
		msg=li[0]+",".join(li[1:])+"\n"
		print msg
		self.starttime=int(time.time() * 1e9)## time started
		ss.send("bor"+"\n") # start sending the message
		ss.send(msg)
		ss.send("eor") # end of sending message
		print "message sent"
		li=[]
		data=None
		while 1:
			print "reply received from anomaly checker"
			data = ss.recv(1024) # answer from anomaly checker
			print data,"received"
			#if not flag: print "len:", len(data.strip()), "data:", data, "flag", flag
			#if not data and not flag: break
			#print data, "alındı"
			#print "Reply from anomaly checker:"
			if data.strip().lower() == "ok":
				self.stoptime=int(time.time() * 1e9) #time stopped
				print "OK message received from anomaly checker"
				li.append("ok")
				break
			if data.strip().lower() != "ok":
				try:
					index=data.index("eoc")
					data=data[:index]
					li.append(data)
					break
				except: 
					#print "Anomaly",data
					li.append(data)
			
		self.stoptime=int(time.time() * 1e9) #time stopped	
		self.reply=li
		ss.close()
		
	# filters the iptables rule list 
	# shows the rules in the ordered way according to their chain
	# python-iptables module is used to parse and read from iptables	
	def sendIpTablesRules(self,ip,port):
		from filterrules import f
		from filterrules import ff
		rslt=[]
		finder(f) # fill the ff

		if len(f["filter"])>1:
			newdic={}
			for x in f["filter"]:
				newdic["filter"]=[x]
				rslt.append(finder(newdic))
			
		if len(ff["filter"])>1:
			newdic={}
			for x in ff["filter"]:
				newdic["filter"]=[x]
				rslt.append(finder(newdic))
		
		li=rslt[1] # rulelist are here
		f=open("file.txt", "w+")
		for k,v in li.iteritems():
			s=str(k)+": "
			ruleli=v.split()
			index=ruleli.index("-p")
			protokol=ruleli[index+1]
			
			try:
				index=ruleli.index("--sport")
				sport=ruleli[index+1]
			except:
				sport="any"
			try:
				index=ruleli.index("--dport")
				dport=ruleli[index+1]
			except:
				dport="any"
			
			srcip=""
			try:
				#print "src:", ruleli
				index=ruleli.index("--src-range")
				srcrange=ruleli[index+1]
				#print srcrange
				li=srcrange.split("-")
				#print li
				a=li[0].split(".")
				b=li[1].split(".")
				
				#print a,b
				
				rli=[]
				#print "len:",len(a)
				for x in xrange(len(a)):
					#print x
					if(a[x] == b[x]):
						rli.insert(x,a[x])
					else:
						rli.insert(x,"*")
				
				srcip=".".join(rli)
				#print "aha",srcip
				
			except:
				try:
					index=ruleli.index("-s")
					srcip=ruleli[index+1]
				except:
					pass
			dstip=""
			try:
				index=ruleli.index("--dst-range")
				dstrange=ruleli[index+1]
				
				li=dstrange.split("-")
				a=li[0].split(".")
				b=li[1].split(".")
				
				rli=[]
				for x in xrange(len(a)):
					if(a[x] == b[x]):
						rli.insert(x,a[x])
					else:
						rli.insert(x,"*")
				
				dstip=".".join(rli)
				
			except:
				try:
					index=ruleli.index("-d")
					dstip=ruleli[index+1]
				except:
					pass
			
			
			index=ruleli.index("-j")
			action=ruleli[index+1]
			
			t=protokol+","+srcip+","+sport+","+dstip+","+dport+","+action.lower()
			filestr=s+t
			
			f.write(filestr+"\n")
		f.close()
		
		while 1:
			try:
				ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
				ss.connect((ip, port))
				break;
			
			except:
				continue #try till connect to the AnomalyChecker
		
		f=open("file.txt","r")
		ss.send("bof"+"\n")
		while 1:
			data=f.readline()
			#print "len",len(data.strip())
			if (len(data.strip())==0): break
			ss.send(data)
		f.close()
		ss.send("eof")
		ss.close()		
		
	# change the * to a range format
	def doFix(self,i):
		srcip1=[]
		srcip2=[]
		li=self.message[i].split(".") 
		for x in xrange(len(li)):
			if li[x] == "*":
				srcip1.insert(x,"1")
				srcip2.insert(x,"254")
			else:
				#print x
				srcip1.insert(x,li[x])
				srcip2.insert(x,li[x])
			
		
		s=".".join(srcip1)+"-"+".".join(srcip2)
		return s
		
	# if there is a range definition in the source ip part of the message convert it to iptables rule	
	def doSrcIP(self,basestr):
		print "girdi", basestr
		
		
		if (self.message[2].find("*") != -1):
			if (self.basestr.find("-m iprange") == -1):
				self.basestr=basestr+"-m iprange "+"--src-range "+self.doFix(2)+" "
			else:
				self.basestr=basestr+"--src-range "+self.doFix(2)+" "
		else:
			self.basestr=basestr+"-s "+self.message[2]+" "
			
		#print self.basestr
			
	# if there is a range definition in the source port part of the message convert it to iptables rule		
	def doSrcPort(self,basestr):
		if (self.message[3].find("any") != -1):
			self.basestr=basestr+"--source-port "+"0:65535"+" "
		else: self.basestr=basestr+"--sport "+self.message[3]+" "
		
		#print self.basestr
		
	# if there is a range definition in the dest ip part of the message convert it to iptables rule	
	def doDstIP(self,basestr):
		
		if (self.message[4].find("*") != -1):
			if (self.basestr.find("-m iprange") == -1):
				self.basestr=basestr+"-m iprange "+"--dst-range "+self.doFix(4)+" "
			else:
				self.basestr=basestr+"--dst-range "+self.doFix(4)+" "
		else:
			self.basestr=basestr+"-d "+self.message[4]+" "
			
		#print self.basestr
			
	# if there is a range definition in the dst port part of the message convert it to iptables tule		
	def doDstPort(self,basestr):
		if (self.message[5].find("any") != -1):
			self.basestr=basestr+"--destination-port "+"0:65535"+" "
		else: self.basestr=basestr+"--dport "+self.message[5]+" "
			
		#print self.basestr
				
	def doTCP(self,basestr):
		#print basestr
		protokol="-p tcp "
		self.basestr=basestr+protokol
		basestr
		self.doSrcIP(self.basestr)
		self.doSrcPort(self.basestr)
		self.doDstIP(self.basestr)
		self.doDstPort(self.basestr)
		
	
	def doUDP(self,basestr):
		protokol="-p udp "
		basestr=basestr+protokol
		self.doSrcIP(basestr)
		self.doSrcPort(basestr)
		self.doDstIP(basestr)
		self.doDstPort(basestr)
		#return basestr
		
	def doICMP(self,basestr):
		protokol="-p icmp "
		basestr=basestr+protokol
		self.doSrcIP(basestr)
		self.doDstIP(basestr)
		#return basestr
	
		
	def doAction(self):
		
		#print basestr
		
		if (self.reply[0].lower() == "ok"):
			s=""
			if self.message[1].lower() == "tcp":
				self.doTCP(self.basestr)
			if self.message[1].lower() == "udp":
				self.doUDP(self.basestr)
			if self.message[1].lower() == "icmp":
				self.doICMP(self.basestr)
			if self.message[6].lower() == "accept":
				s=self.basestr+"-j ACCEPT" 
			if self.message[6].lower() == "reject":
				s=self.basestr+"-j REJECT"
			if self.message[6].lower() == "drop":
				s=self.basestr+"-j DROP"
			if self.message[6].lower() == "deny":
				s=self.basestr+"-j DROP"
				
			print "Adding rule:"	
			print s # burada iptablesa yazılacak
			os.system(s)
			print "Done"
			
			self.sendIpTablesRules(ANOMALYHOST,ANOMALYPORT)
			
		else:
			print "Anomaly detected:"
			
			for x in self.reply:
				print x
		
	if __name__=="__main__":
		
		from araci import Mediator
		m=Mediator()
		m.listenForMessage(PORTLISTEN)
		m.sendAndReceive(ANOMALYHOST,ANOMALYPORT)
		print "Time for reply:", (m.stoptime-m.starttime)/1e9, "nanoseconds"
		m.startime=int(time.time() * 1e9)
		m.doAction()
		m.stoptime=int(time.time() * 1e9)
		print "Time for writing rule and sending the current table:", (m.stoptime-m.starttime)/1e9, "nanoseconds"
		
	

